package org.example;

import javassist.*;
import java.lang.reflect.Method;

/**
 * 演示: 通过 javassist程序生成一个复杂的class文件, 包含有参有返回值的方法.
 * 并调用其中的方法.
 */
public class AppGenNewComplexCzBySsist {
    public static void main(String[] args) throws Exception {

        CtClass ctClass = genComplexClass();
        Object returns = invokeMethod(ctClass, "say");
        System.out.println(returns);
    }

    public static CtClass genComplexClass() throws Exception{
        String postFix = "target/genComplexCzByJs";
        String genClassDir = System.getProperty("user.dir") + "/javassistTest/"+postFix;
        System.out.println("生成的class文件放在"+postFix);

        ClassPool cp = ClassPool.getDefault();
        CtClass ctClass = cp.makeClass("com.scy.javassist.Hello");

        //添加一个int类型的，名字为value的变量
        CtField ctField = new CtField(CtClass.intType,"value",ctClass);
        ctField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(ctField);

        //为value变量添加set方法
        CtMethod setValue = new CtMethod(CtClass.voidType, "setValue", new CtClass[]{CtClass.intType}, ctClass);
        setValue.setModifiers(Modifier.PUBLIC);
        setValue.setBody("{ this.value = $1; }");
        ctClass.addMethod(setValue);

        //为value变量添加get方法
        CtMethod getValue = new CtMethod(CtClass.intType, "getValue", new CtClass[]{}, ctClass);
        getValue.setModifiers(Modifier.PUBLIC);
        getValue.setBody("{ return this.value; }");
        ctClass.addMethod(getValue);

        /**
         CtMethod（...）源代码：
         public CtMethod(CtClass returnType,//这个方法的返回值类型，
         String mname, //（method name）方法的名字是什么
         CtClass[] parameters, //方法传入的参数类型是什么
         CtClass declaring //添加到哪个类中
         ) {....}
         */
        //添加带入参和返回值的方法
        CtMethod sayMethod = new CtMethod(cp.getCtClass("java.lang.String"), "say",
                new CtClass[]{cp.getCtClass("java.lang.String"),cp.getCtClass("java.lang.String")}, ctClass);
        sayMethod.setModifiers(Modifier.PUBLIC);
        StringBuilder builder = new StringBuilder();
        builder.append("{\n System.out.println(\"say方法执行了\");\n");
        builder.append("return \"返回值是姓名=\"+$1+\" ,年龄=\" +$2 ; }\n");
        sayMethod.setBody(builder.toString());
        ctClass.addMethod(sayMethod);

        //写入本地,写入
        ctClass.writeFile(genClassDir);

        return ctClass;
    }

    public static Object invokeMethod(CtClass ctClass,String methodName) throws Exception{
        Class<?> aClass = ctClass.toClass();
        Object o = aClass.newInstance();
        Method say = aClass.getDeclaredMethod(methodName, String.class,String.class);
        Object returnVal = say.invoke(o, "时春跃","33");
       return returnVal;
    }
}